#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <cstring>
#include <jsoncpp/json/json.h>
#include <unistd.h>

namespace protocol_ns
{
    const char *SEP = "\r\n";
    // "len"\r\n"{
    // "len"\r\n"{             }"
    // "len"\r\n"{             }"\r\n;
    // "len"\r\n"{             }"\r\n"len";
    // "len"\r\n"{             }"\r\n"len"\r\n"{             }";
    // "len"\r\n"{             }"\r\n"len"\r\n"{             }"\r\n
    // 将数据中的一个报文字符串提取出来,并将数据中的这个报文删除
    std::string Decode(std::string &buffer)
    {
        // 找到第一个分隔符的位置 \r\n
        auto pos = buffer.find(SEP);
        if (pos == std::string::npos)
        {
            // 没有找到一个分隔符, 返回空串
            return "";
        }

        // 有一个分隔符 --> 将报文长度字符串提取出来
        std::string len_str = buffer.substr(0, pos);
        if (len_str.empty())
            return std::string();
        int package_len = std::stoi(len_str);

        // 包含一个完整报文的最短长度
        int total_len = package_len + 2 * strlen(SEP) + len_str.size();
        if (buffer.size() < total_len)
            return std::string();

        // 得到报文
        std::string package = buffer.substr(pos + strlen(SEP), package_len);
        // 删除第一个完整的报文字符串
        buffer.erase(0, total_len);
        return package;
    }

    std::string Encode(const std::string& json_str)
    {
        // 求出报头的长度
        int json_str_len = json_str.size();
        std::string protocol_str = std::to_string(json_str_len);
        protocol_str += SEP;
        protocol_str += json_str;
        protocol_str += SEP;
        return protocol_str;
    }

    class Request
    {
    public:
        Request()
        {
        }

        Request(int x, int y, char oper)
            : _data_x(x), _data_y(y), _oper(oper)
        {
        }

        // 将序列化的结果作为输出型参数带出
        bool Serialize(std::string *out)
        {
            // 将结构对象转换为字符串
            Json::Value root;
            root["x"] = _data_x;
            root["y"] = _data_y;
            root["oper"] = _oper;

            Json::FastWriter writer;
            *out = writer.write(root);
            return true;
        }

        // 反序列化，将反序列化的结果直接填充到调用对象中(使用Jsoncpp进行操作)
        bool DeSerialize(const std::string &in)
        {
            // 将字符串转换为结构对象
            Json::Value root;
            Json::Reader reader;
            bool res = reader.parse(in, root);
            if (!res)
                return false;

            _data_x = root["x"].asInt();
            _data_y = root["y"].asInt();
            _oper = root["oper"].asInt();

            return true;
        }

    public:
        int _data_x;
        int _data_y;
        char _oper;
    };

    class Response
    {
    public:
        Response()
        {
        }

        Response(int result, int code)
            : _result(result), _code(code)
        {
        }

        // 将序列化的结果作为输出型参数带出
        bool Serialize(std::string *out)
        {
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;

            Json::FastWriter writer;
            *out = writer.write(root);
            return true;
        }

        // 反序列化，将反序列化的结果直接填充到调用对象中
        bool DeSerialize(const std::string &in)
        {
            Json::Value root;
            Json::Reader reader;
            bool res = reader.parse(in, root);

            if (!res)
                return false;
            _result = root["result"].asInt();
            _code = root["code"].asInt();

            return true;
        }

    public:
        int _result;
        int _code; // 运算状态
    };

    class Factory
    {
    public:
        Factory()
        {
            srand(time(nullptr) ^ getpid());
            opers = "+-*/%^|&"; 
        }

        std::shared_ptr<Request> BuildRequest()
        {
            int x = rand() % 10 + 1;
            usleep(x * 10);
            int y = rand() % 5;
            usleep(y * x * 5);
            char oper = opers[rand() % opers.size()];

            return std::make_shared<Request>(x, y, oper);
        }

        std::shared_ptr<Response> BuildResponse()
        {
            return std::make_shared<Response>();
        }
        
        ~Factory()
        {}
    private:
        std::string opers;
    };
}